﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Data.SQLite;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using ParkingLot.Entitys.Enums;
using ParkingLot.Utility.CollectionEntity;
using ParkingLot.Utility.Extend;

namespace ParkingLot.Utility.LogHelps
{
    /* 传入的日志并不是马上记录  ，而是放入字典  后台线程从字典取值()*/

    /// <summary>
    /// 写日志的帮助类
    /// </summary>
    public class LogHelp
    {
        #region 私有
        /// <summary>
        /// 日志文件夹路径
        /// </summary>
        private static string m_LogFolderPath = $"{AppDomain.CurrentDomain.BaseDirectory}{ConfigManager.AppSettings["LogPath"].Value}\\{new DateTime().GetCurTime().ToString("yyyyMMdd")}";

        public static int SaveDays = 30;

        /// <summary>
        /// 日志集合(线程安全的日志集合)
        /// </summary>
        private static ConcurrentQueue<LogEncity> m_LogCurrentQueue = new ConcurrentQueue<LogEncity>();

        #endregion

        static LogHelp()
        {
            //初始化写日志的线程
            InitLogThread();
            //定时清除日志
            ClearLog();
        }

        #region 私有

        /// <summary>
        /// 初始化写日志的线程
        /// </summary>
        private static void InitLogThread()
        {
            Thread thread = new Thread(ThreadAction);
            thread.IsBackground = true;
            thread.Start();
        }

        /// <summary>
        /// 定期清除日志
        /// </summary>
        private static void ClearLog()
        {
            Thread thread = new Thread(() =>
              {
                  while (true)
                  {
                      try
                      {
                          string name = DateTime.Now.AddDays(-SaveDays).ToString("yyyyMMdd");
                          string path = $"{AppDomain.CurrentDomain.BaseDirectory}{ConfigManager.AppSettings["LogPath"].Value}";
                          DirectoryInfo root = new DirectoryInfo(path);
                          DirectoryInfo[] dics = root.GetDirectories();
                          foreach (DirectoryInfo directoryInfo in dics)
                          {
                              if (directoryInfo.CreationTime < DateTime.Now.AddDays(-SaveDays))
                              {
                                  DeleteDir(directoryInfo.FullName);
                              }
                          }
                      }
                      catch (Exception exception)
                      {
                          LogHelp.AddLog<LogEncity>(exception);
                      }
                      Thread.Sleep(new TimeSpan(0, 4, 0, 0));
                  }

              });
            thread.IsBackground = true;
            thread.Start();
        }

        //删除文件夹
        public static bool DeleteDir(string file)
        {

            try
            {

                //去除文件夹和子文件的只读属性
                //去除文件夹的只读属性
                System.IO.DirectoryInfo fileInfo = new DirectoryInfo(file);
                fileInfo.Attributes = FileAttributes.Normal & FileAttributes.Directory;

                //去除文件的只读属性
                System.IO.File.SetAttributes(file, System.IO.FileAttributes.Normal);

                //判断文件夹是否还存在
                if (Directory.Exists(file))
                {

                    foreach (string f in Directory.GetFileSystemEntries(file))
                    {

                        if (File.Exists(f))
                        {
                            //如果有子文件删除文件
                            File.Delete(f);
                            Console.WriteLine(f);
                        }
                        else
                        {
                            //循环递归删除子文件夹
                            DeleteDir(f);
                        }

                    }

                    //删除空文件夹

                    Directory.Delete(file);

                }
                return true;

            }
            catch (Exception ex) // 异常处理
            {
                return false;
            }

        }



        /// <summary>
        /// 写日志的方法
        /// </summary>
        private static void ThreadAction()
        {
            bool sleepTimes = false;
            while (true)
            {
                try
                {
                    if (m_LogCurrentQueue.Count == 0)
                    {
                        Thread.Sleep(100);
                        continue;
                    }

                    LogEncity log;
                    //从并发集合中取出数据
                    bool bolHaveValue = m_LogCurrentQueue.TryDequeue(out log);
                    if (bolHaveValue == false)
                    {
                        Thread.Sleep(100);
                        continue;
                    }

                    //IO写日志
                    if (log != null)
                    {
                        //bool bolWirteStates = TryInsert(log);
                        //if (log.LogType == LogType.Error)
                        //{
                        TryWrite(log);
                        //}
                    }

                }
                catch (Exception exception)
                {
                    LogEncity logEncity = new LogEncity()
                    {
                        LogTime = new DateTime().GetCurTime(),
                        Message = $"日志写入异常{exception.Message}",
                        LogType = LogType.Error
                    };
                    //AddLog(logEncity);
                }
            }
        }

        private static string GetWriteValue(List<LogEncity> lisLogEncity)
        {
            StringBuilder sbLog = new StringBuilder();
            foreach (var item in lisLogEncity)
            {
                sbLog.AppendLine("\r\n--------------------------------------------");
                sbLog.AppendLine($"\r\n{item.LogTime.GetString()}");
                sbLog.AppendLine($"\r\n{item.Message}");
            }
            return sbLog.ToString();
        }

        /// <summary>
        /// 日志实体写日志文件
        /// </summary>
        /// <param name="logEncity"></param>
        /// <returns></returns>
        private static bool TryWrite(LogEncity logEncity)
        {
            try
            {
                m_LogFolderPath = $"{AppDomain.CurrentDomain.BaseDirectory}{ConfigManager.AppSettings["LogPath"].Value}\\{new DateTime().GetCurTime().ToString("yyyyMMdd")}";
                if (!Directory.Exists(m_LogFolderPath))
                {
                    Directory.CreateDirectory(m_LogFolderPath);
                }
                string logFileName = GetLogFileName(logEncity);
                string logFilePath = $"{m_LogFolderPath}\\{logFileName}";

                string logMessage = GetWriteValue(logEncity);
                File.AppendAllText(logFilePath, logMessage, Encoding.Default);
                //using (StreamWriter sw = File.AppendText(logFilePath))
                //{
                //sw.Write(logMessage);
                //}
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }



        public static bool TryInsert(LogEncity logEncity)
        {
            try
            {
                string path = $"{AppDomain.CurrentDomain.BaseDirectory}{ConfigManager.AppSettings["LogPath"].Value}\\Logs.db";
                SQLiteConnection cn = new SQLiteConnection("data source=" + path);
                cn.Open();
                SQLiteCommand cmd = cn.CreateCommand();
                SQLiteTransaction tr = cn.BeginTransaction();
                try
                {
                    cmd.CommandText = "INSERT INTO T_Base_LogEntitys(LogID,Content,LogTime,LogType,RelationID) VALUES(@LogID,@Content,@LogTime,@LogType,@RelationID)";
                    cmd.Parameters.Add("LogID", DbType.String).Value = logEncity.LogID;
                    cmd.Parameters.Add("Content", DbType.String).Value = logEncity.Message;
                    cmd.Parameters.Add("LogTime", DbType.DateTime).Value = logEncity.LogTime;
                    cmd.Parameters.Add("LogType", DbType.String).Value = logEncity.LogType.ToString();
                    cmd.Parameters.Add("RelationID", DbType.String).Value = logEncity.RelationID;
                    cmd.ExecuteNonQuery();

                    cmd.CommandText = "INSERT INTO T_Log_LogTypeCates(LogID,LogType) VALUES(@LogID,@LogType)";
                    cmd.Parameters.Clear();
                    cmd.Parameters.Add("LogID", DbType.String);
                    cmd.Parameters.Add("LogType", DbType.String);
                    foreach (string category in logEncity.lisCategories)
                    {
                        cmd.Parameters["LogID"].Value= logEncity.LogID;
                        cmd.Parameters["LogType"].Value = category;
                        cmd.ExecuteNonQuery();
                    }
                    tr.Commit();
                    return true;
                }
                catch (Exception e)
                {
                    tr.Rollback();
                    return false;
                }
            }
            catch (Exception e)
            {
                return false;
            }
          
        }

        /// <summary>
        /// 获取日志文件路径
        /// </summary>
        /// <returns></returns>

        private static string GetLogFileName(LogEncity logEncity)
        {

            string fileName = $"{new DateTime().GetCurTime().ToLongDateString()}log.txt";
            switch (logEncity.LogType)
            {
                case LogType.None:
                    fileName = logEncity.SaveFileName;
                    break;
                case LogType.SysRun:
                    fileName = $"{LogType.SysRun}.txt";
                    break;
                case LogType.Error:
                    fileName = $"{LogType.Error}.txt";
                    break;
                case LogType.Init:
                    fileName = $"{LogType.Init}.txt";
                    break;
                case LogType.KeyDownLog:
                    fileName = $"{LogType.KeyDownLog}.txt";
                    break;
                case LogType.AlgroLog:
                    fileName = $"{LogType.AlgroLog}.txt";
                    break;
                case LogType.ChoiceLog:
                    fileName = $"{LogType.ChoiceLog}.txt";
                    break;
                case LogType.PublishLog:
                    fileName = $"{LogType.PublishLog}.txt";
                    break;
                case LogType.Fabulous:
                    fileName = $"{LogType.Fabulous}.txt";
                    break;
            }
            return fileName;
        }

        /// <summary>
        /// 根据日志信息获取日志内容
        /// </summary>
        /// <param name="logEncity"></param>
        /// <returns></returns>
        private static string GetWriteValue(LogEncity logEncity)
        {
            StringBuilder sbLog = new StringBuilder();

            sbLog.AppendLine("\r\n--------------------------------------------");
            sbLog.Append($"\r\n{logEncity.LogTime.GetString()}");
            sbLog.AppendLine($"\r\n{logEncity.Message}");

            return sbLog.ToString();
        }

        #endregion

        #region 公共方法

        /// <summary>
        /// 添加日志
        /// </summary>
        /// <param name="logEncity"></param>
        public static void AddLog(LogEncity logEncity)
        {
            m_LogCurrentQueue.Enqueue(logEncity);
        }

        /// <summary>
        /// 添加日志
        /// </summary>
        /// <param name="logEncity"></param>
        public static void AddLog<T>(T logEncity) where T : LogEncity
        {
            m_LogCurrentQueue.Enqueue(logEncity);
        }

        /// <summary>
        /// 添加日志
        /// </summary>
        /// <param name="logEncity"></param>
        public static void AddLog(string error, Exception exception)
        {
            LogEncity logEncity = new LogEncity(error, exception);
            m_LogCurrentQueue.Enqueue(logEncity);
        }

        /// <summary>
        /// 通过实体添加日志
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        public static void AddEntityLog<T>(T t)
        {
            string error = "";
            try
            {
                if (!CollectionSRHelp<T>.HaveSetPath)
                {
                    CollectionSRHelp<T>.SetSavePath(ConfigManager.AppSettings["LogPath"].Value, $"{typeof(T).Name}.xml");
                }
                CollectionSRHelp<T>.Save(t, out error);
                if (!string.IsNullOrEmpty(error))
                {
                    LogHelp.AddLog<LogEncity>(error);
                }
            }
            catch (Exception e)
            {
               LogHelp.AddLog<LogEncity>(e);
            }
           
        }

        /// <summary>
        /// 接口异常
        /// </summary>
        /// <param name="error"></param>
        /// <param name="exception"></param>
        public static void AddInterFaceLog(string error, Exception exception = null)
        {
            LogEncity logEncity = new LogEncity();
            logEncity.LogType = LogType.InterfaceLog;
            logEncity.Message = error;
            if (exception != null)
            {
                logEncity.Message += exception.ToString();
            }
            m_LogCurrentQueue.Enqueue(logEncity);
        }

        public static void Dispose()
        {

        }

        #endregion


    }
}
